package middleware

import (
	"bytes"
	"fmt"
	"gitee.com/goddesszz/gocommon/myutil"
	"github.com/gin-gonic/gin"
	"github.com/samber/lo"
	"github.com/sirupsen/logrus"
	"io"
	"monoblog/domain/model"
	"monoblog/domain/service"
	"monoblog/util"
	"net/http"
	"net/url"
	"strings"
	"time"
)

func AccessView(ctx *gin.Context) {
	var uri = ctx.Request.RequestURI

	logrus.Debug(fmt.Sprintf("==> 访问页面 %s", uri))

	ctx.Next() //放行，执行下去

}

// 访问监控白名单
var whiteList = []string{
	"/rest/admin/stream-console",
	"/rest/admin/access-log",
}

// AccessMonitor 监控访问接口的请求参数、响应数据 及 消耗时间
func AccessMonitor(ctx *gin.Context) {
	var uri = ctx.Request.RequestURI //含?后的参数
	var path = ctx.Request.URL.Path  //不含?后的参数
	var method = ctx.Request.Method
	var headers = ctx.Request.Header
	// 获取处理函数名
	var handlerName = ctx.HandlerName()

	if lo.Contains(whiteList, path) {
		ctx.Next() //白名单放行，执行下去
		return
	}

	logrus.Debug(fmt.Sprintf("==> 访问接口 %s \t [%s] ↲", uri, handlerName))

	ctx.Request.ParseForm() //先要解析form

	//var params = ctx.Request.URL.Query()
	//if len(params) > 0 {
	//	fmt.Println("[minitor] -> "+"query params = ", myutil.JsonToString(params)) //ok
	//}
	//var postForm = ctx.Request.PostForm
	//if len(postForm) > 0 {
	//	fmt.Println("[minitor] -> "+"form params = ", myutil.JsonToString(postForm)) //ok
	//}
	//var form = ctx.Request.Form // 相当于 form + query合并为Form

	var form = ctx.Request.PostForm

	var bodyJson = readBody(ctx.Request) // 接收 body JSON

	var rawQuery = ctx.Request.URL.RawQuery

	// 生成请求唯一ID
	aid := util.Uuid()
	ctx.Set("aid", aid) //存储到gin上下文

	startTime := time.Now().UnixMilli()

	ctx.Next() //放行，执行下去

	endTime := time.Now().UnixMilli()

	go func() {
		_ = service.GetAccessLogService().Save(ctx, &model.AccessLog{
			AID:         aid,
			HandlerName: handlerName,
			Path:        path,
			HttpMethod:  method,
			XHeaders:    printXHeaders(headers),
			Params:      util.JsonStrErasePassword(printForm(form)) + util.JsonStrErasePassword(bodyJson) + rawQuery,
			CostMillis:  int(endTime - startTime),
			ClientIp:    ctx.ClientIP(),
		})
	}()
}

func readBody(request *http.Request) string {
	var bodyJson string

	// 只处理Content-Type为JSON的请求
	contentType := request.Header.Get("Content-Type")
	if strings.HasPrefix(contentType, "application/json") {
		// 读取原始请求体
		bodyBytes, err := io.ReadAll(request.Body)

		if err == nil {
			request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) // 重新包装请求体，让后续处理能正常读取
			bodyJson = string(bodyBytes)
		}
	}
	return bodyJson
}

// printHeaders 将headers映射转换为格式化的字符串
func printXHeaders(headers http.Header) string {
	var buf bytes.Buffer // 相当于Java的StringBuilder

	for k, v := range headers {
		if strings.HasPrefix(strings.ToLower(k), "x-") {
			fmt.Fprintf(&buf, "\t%-20s : %s\n", k, strings.Join(v, ","))
		}
	}
	return buf.String()
}

func printForm(form url.Values) string {
	if len(form) > 0 {
		return myutil.JsonToString(form)
	} else {
		return ""
	}
}
